﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using ArcGIS.Core.Data;
using ArcGIS.Desktop.Core;
using ArcGIS.Desktop.Framework.Threading.Tasks;
using CCTool.Scripts.Manager;
using CCTool.Scripts.ToolManagers;
using CCTool.Scripts.ToolManagers.Extensions;
using CCTool.Scripts.ToolManagers.Managers;
using NPOI.OpenXmlFormats.Vml;
using Table = ArcGIS.Core.Data.Table;

namespace CCTool.Scripts.DataPross.FeatureClasses
{
    /// <summary>
    /// Interaction logic for AdjustmentsTool.xaml
    /// </summary>
    public partial class AdjustmentsTool : ArcGIS.Desktop.Framework.Controls.ProWindow
    {
        // 工具设置标签
        readonly string toolSet = "AdjustmentsTool";

        public AdjustmentsTool()
        {
            InitializeComponent();

            // 初始化参数选项
            combox_areaType.Text = BaseTool.ReadValueFromReg(toolSet, "areaType", "投影面积");
            combox_unit.Text = BaseTool.ReadValueFromReg(toolSet, "unit", "平方米");
            combox_digit.Text = BaseTool.ReadValueFromReg(toolSet, "digit", "2");

        }

        // 定义一个进度框
        private ProcessWindow processwindow = null;
        string tool_name = "面积平差";

        private void combox_fc_DropDown(object sender, EventArgs e)
        {
            UITool.AddFeatureLayersToComboxPlus(combox_fc);
        }

        private void combox_field_DropDown(object sender, EventArgs e)
        {
            UITool.AddFloatFieldsToComboxPlus(combox_fc.ComboxText(), combox_field);
        }

        private void combox_land_DropDown(object sender, EventArgs e)
        {
            UITool.AddFeatureLayersToComboxPlus(combox_land);
        }

        private async void btn_go_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                // 获取参数
                string fc_path = combox_fc.ComboxText();
                string fc_field = combox_field.ComboxText();
                string land_path = combox_land.ComboxText();
                string areaType = combox_areaType.Text[..2];
                string unit = combox_unit.Text;
                int digit = combox_digit.Text.ToInt();

                bool isFieldOpen = (bool)check_fd.IsChecked;
                string areaField = combox_areaField.ComboxText();

                // 默认数据库位置
                var gdb_path = Project.Current.DefaultGeodatabasePath;
                // 工程默认文件夹位置
                string folder_path = Project.Current.HomeFolderPath;

                // 判断参数是否选择完全
                if (fc_path == "" || fc_field == "" || land_path == "" || areaType == "" || unit == "" || combox_digit.Text == "")
                {
                    MessageBox.Show("有必选参数为空！！！");
                    return;
                }

                // 写入本地
                BaseTool.WriteValueToReg(toolSet, "areaType", areaType+"面积");
                BaseTool.WriteValueToReg(toolSet, "unit", unit);
                BaseTool.WriteValueToReg(toolSet, "digit", digit);

                // 打开进度框
                ProcessWindow pw = UITool.OpenProcessWindow(processwindow, tool_name);
                pw.AddMessageTitle(tool_name);

                Close();
                await QueuedTask.Run(() =>
                {
                    pw.AddMessageStart("检查数据");
                    // 检查数据
                    List<string> errs = CheckData(fc_path, land_path);
                    // 打印错误
                    if (errs.Count > 0)
                    {
                        foreach (var err in errs)
                        {
                            pw.AddMessageMiddle(10, err, Brushes.Red);
                        }
                        return;
                    }

                    // 取消选择，避免覆盖结果丢失图斑
                    MapCtlTool.UnSelectAllFeature(fc_path);

                    pw.AddMessageMiddle(10, "平差计算", Brushes.Gray);
                    string resultLayer = "";

                    if (isFieldOpen == true && areaField is not null && areaField != "")
                    {
                        resultLayer = Adjustment(fc_path, land_path, gdb_path + @"\Adjustment", areaType, unit, digit, areaField);
                    }
                    else
                    {
                        // 平差计算
                        resultLayer = Adjustment(fc_path, land_path, gdb_path + @"\Adjustment", areaType, unit, digit);
                    }

                    pw.AddMessageMiddle(50, "结果赋值", Brushes.Gray);
                    // 字段赋值
                    Arcpy.CalculateField(resultLayer, fc_field, $"!{areaType}!");

                    pw.AddMessageMiddle(20, "覆盖图层", Brushes.Gray);
                    // 返回覆盖图层
                    string fcFullPath = fc_path.TargetLayerPath();
                    Arcpy.CopyFeatures(resultLayer, fcFullPath, true);

                    pw.AddMessageMiddle(20, "删除中间字段", Brushes.Gray);
                    // 删除中间字段
                    List<string> fieldList = GisTool.GetFieldsNameFromTarget(fc_path);   // 获取原始字段
                    string fields = "";
                    foreach (var field in fieldList)
                    {
                        fields += field + ";";
                    }
                    string re = fields.Substring(0, fields.Length - 1);
                    Arcpy.DeleteField(fcFullPath, re, "KEEP_FIELDS");
                });
                pw.AddMessageEnd();
            }
            catch (Exception ee)
            {
                MessageBox.Show(ee.Message + ee.StackTrace);
                return;
            }
        }

        private void combox_areaField_DropOpen(object sender, EventArgs e)
        {
            string fd = combox_fc.ComboxText();
            if (fd is not null && fd != "")
            {
                UITool.AddFloatFieldsToComboxPlus(fd, combox_areaField);
            }
        }


        private void btn_help_Click(object sender, RoutedEventArgs e)
        {
            string url = "https://blog.csdn.net/xcc34452366/article/details/135822374?spm=1001.2014.3001.5501";
            UITool.Link2Web(url);
        }

        private List<string> CheckData(string fc_path, string land_path)
        {
            List<string> result = new List<string>();
            // 检查 land_path是否多部件，多要素
            int count = Arcpy.GetCount(land_path);
            if (count > 1)
            {
                result.Add("范围图层存在多个要素，只能保留一个");
            }
            else if(count == 1)
            {
                string countResult = CheckTool.CheckMultiPart(land_path);

                if (countResult != "")
                {
                    result.Add(countResult);
                }
            }

            // 检查用地和范围是否完全重合
            string def_gdb = Project.Current.DefaultGeodatabasePath;
            string re = $@"{def_gdb}\re";
            Arcpy.SymDiff(fc_path, land_path, re);
            int reCount = Arcpy.GetCount(re);
            if (reCount > 0)
            {
                result.Add("用地图层和范围图层不完全重合。");
            }
            Arcpy.Delect(re);

            return result;
        }


        // 裁剪平差计算
        private string Adjustment(string yd, string area, string clipfc_sort, string area_type = "投影", string unit = "平方米", int digit = 2, string areaField = "")
        {
            string def_gdb = Project.Current.DefaultGeodatabasePath;
            string area_line = def_gdb + @"\area_line";
            string clipfc = def_gdb + @"\clipfc";
            string clipfc_sta = def_gdb + @"\clipfc_sta";
            string clipfc_updata = def_gdb + @"\clipfc_updata";

            // 单位系数设置
            double unit_xs = unit switch
            {
                "平方米" => 1.0,
                "公顷" => 10000.0,
                "平方公里" => 1000000.0,
                "亩" => 666.66667,
                _ => 1.0
            };
            


            // 计算图斑的投影面积和图斑面积
            Arcpy.Clip(yd, area, clipfc);

            Arcpy.AddField(clipfc, area_type, "DOUBLE");
            Arcpy.AddField(area, area_type, "DOUBLE");

            if (areaField != "")
            {
                area_type = "图斑";

                Arcpy.CalculateField(clipfc, area_type, $"!{areaField}!");
                Arcpy.Statistics(clipfc, clipfc_sta, area_type, "");          // 汇总
                // 计算范围的投影面积和图斑面积
                Arcpy.CalculateField(area, area_type, $"round(!shape.geodesicarea!/{unit_xs},{digit})");

            }
            else
            {
                if (area_type == "投影")
                {
                    Arcpy.CalculateField(clipfc, area_type, $"round(!shape_area!/{unit_xs},{digit})");
                    Arcpy.Statistics(clipfc, clipfc_sta, area_type, "");          // 汇总
                    // 计算范围的投影面积和图斑面积
                    Arcpy.CalculateField(area, area_type, $"round(!shape_area!/{unit_xs},{digit})");
                }
                else if (area_type == "图斑")
                {
                    Arcpy.CalculateField(clipfc, area_type, $"round(!shape.geodesicarea!/{unit_xs},{digit})");
                    Arcpy.Statistics(clipfc, clipfc_sta, area_type, "");          // 汇总
                    // 计算范围的投影面积和图斑面积
                    Arcpy.CalculateField(area, area_type, $"round(!shape.geodesicarea!/{unit_xs},{digit})");
                }
            }

            // 获取投影面积，图斑面积
            double mj_fc = clipfc_sta.TargetCellValue($"SUM_{area_type}", "").ToDouble();
            double mj_area = area.TargetCellValue(area_type, "").ToDouble();

            // 面积差值
            double dif_mj = Math.Round(Math.Round(mj_area, digit) - Math.Round(mj_fc, digit), digit);

            // 空间连接，找出变化图斑（即需要平差的图斑）
            Arcpy.FeatureToLine(area, area_line);
            if (GisTool.IsHaveFieldInTarget(area_line, "BJM"))
            {
                Arcpy.DeleteField(area_line, "BJM", "KEEP_FIELDS");
            }
            Arcpy.SpatialJoin(clipfc, area_line, clipfc_updata);
            Arcpy.AddField(clipfc_updata, "平差", "TEXT");
            Arcpy.CalculateField(clipfc_updata, "平差", "''");
            // 排序
            Arcpy.Sort(clipfc_updata, clipfc_sort, "Shape_Area DESCENDING", "UR");
            double area_total = 0;

            // 获取Table
            using Table table = clipfc_sort.TargetTable();

            // 汇总变化图斑的面积
            using (RowCursor rowCursor = table.Search())
            {
                while (rowCursor.MoveNext())
                {
                    using Row row = rowCursor.Current;
                    int va = row["Join_Count"].ToString().ToInt();
                    if (va == 1)     // 如果是变化图斑
                    {
                        area_total += row[area_type].ToString().ToDouble();
                    }
                }
            }
            // 第一轮平差
            double area_pc_1 = 0;
            using (RowCursor rowCursor1 = table.Search())
            {
                while (rowCursor1.MoveNext())
                {
                    using Row row = rowCursor1.Current;
                    int va = row["Join_Count"].ToString().ToInt();
                    if (va == 1)
                    {
                        double area_1 = row[area_type].ToString().ToDouble();
                        // 单个图斑需要平差的值
                        double area_pc = Math.Round(area_1 / area_total * dif_mj, digit);
                        area_pc_1 += area_pc;
                        // 面积平差
                        row[area_type] = area_1 + area_pc;

                        row.Store();
                    }
                }
            }
            // 计算剩余平差面积，进行第二轮平差
            double area_total_next = Math.Round(dif_mj - area_pc_1, digit);
            using (RowCursor rowCursor2 = table.Search())
            {
                while (rowCursor2.MoveNext())
                {
                    using Row row = rowCursor2.Current;
                    // 最小平差值
                    double diMin = Math.Round(Math.Pow(0.1, digit), digit);

                    int va = row["Join_Count"].ToString().ToInt();
                    if (va == 1)
                    {
                        double area_2 = row[area_type].ToString().ToDouble();
                        // 面积平差
                        if (area_total_next > 0)
                        {
                            row[area_type] = area_2 + diMin;
                            area_total_next -= diMin;
                        }
                        else if (area_total_next < 0)
                        {
                            row[area_type] = area_2 - diMin;
                            area_total_next += diMin;
                        }
                        row.Store();
                    }
                }
            }
            // 删除中间要素
            List<string> all = new List<string>() { "area_line", "clipfc", "clipfc_sta", "clipfc_updata" };
            foreach (var item in all)
            {
                Arcpy.Delect(def_gdb + @"\" + item);
            }
            // 返回值
            return clipfc_sort;
        }


        
    }
}
